package org.example.commodity.activity.service;

import cn.hutool.core.util.ObjectUtil;
import org.example.commodity.activity.entity.ActivityInfo;
import org.example.commodity.activity.exception.CommodityActivityException;
import org.example.commodity.activity.util.CommodityActivityRedisUtil;
import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

@Slf4j
public abstract class BaseCommodityActivityRedisService<T extends ActivityInfo> {

    private final CommodityActivityRedisUtil commodityActivityRedisUtil;
    public static final String ACTIVITY_INFO_KEY_FORMAT = "%s_%s";
    public static final String CUSTOMER_PURCHASE_kEY_FORMAT = "customer_purchase_%s_%s_%s";
    public static final String ACTIVITY_STOCKS_kEY_FORMAT = "%s_%s_%s";

    public BaseCommodityActivityRedisService(CommodityActivityRedisUtil commodityActivityRedisUtil) {
        this.commodityActivityRedisUtil = commodityActivityRedisUtil;
    }


    /**
     * 缓存活动信息
     */
    public void cacheActivityInfo(T activityInfo) {
        if (LocalDateTime.now().isAfter(activityInfo.getEndTime())) {
            log.info("{}秒杀已结束!", activityInfo.getId());
        }
        long seconds = Duration.between(LocalDateTime.now(), activityInfo.getEndTime()).toSeconds();
        commodityActivityRedisUtil.set(formatActivityKey(activityInfo.getCommoditySkuId()), activityInfo, seconds, TimeUnit.SECONDS);
        setActivityStocks(activityInfo.getId(), activityInfo.getCommoditySkuId(), activityInfo.getRemainingStocks(), seconds);
    }

    /**
     * 缓存活动库存
     */
    public void setActivityStocks(Long activityId, Long commoditySkuId, Integer stocks, long seconds) {
        String key = formatActivityStocksKey(activityId, commoditySkuId);
        commodityActivityRedisUtil.set(key, stocks, seconds, TimeUnit.SECONDS);
    }

    /**
     * 增加或减少活动库存
     */
    public void addActivityStocks(Long activityId, Long commoditySkuId, Integer quantity) {
        commodityActivityRedisUtil.increment(formatActivityStocksKey(activityId, commoditySkuId), -1L * quantity);
    }

    /**
     * 获取活动库存
     */
    public Integer getCommodityStocks(Long activityId, Long commoditySkuId) {
        return Integer.valueOf(commodityActivityRedisUtil.get(formatActivityStocksKey(activityId, commoditySkuId)));
    }

    /**
     * 移除活动相关信息
     */
    public void removeActivityInfo(Long commoditySkuId) {
        commodityActivityRedisUtil.delete(formatActivityKey(commoditySkuId));
        commodityActivityRedisUtil.deleteKeys(String.format(ACTIVITY_STOCKS_kEY_FORMAT, getActivityType(), commoditySkuId, "*"));
        commodityActivityRedisUtil.deleteKeys(String.format(CUSTOMER_PURCHASE_kEY_FORMAT, getActivityType(), commoditySkuId, "*"));
    }

    /**
     * 获取活动信息
     */
    public ActivityInfo getActivityInfo(Long commoditySkuId) {
        String key = formatActivityKey(commoditySkuId);
        return commodityActivityRedisUtil.getObject(key, ActivityInfo.class);
    }

    /**
     * 设置活动类型
     */
    protected abstract String getActivityType();


    private String formatActivityKey(Long commoditySkuId) {
        return String.format(ACTIVITY_INFO_KEY_FORMAT, getActivityType(), commoditySkuId);
    }


    private String formatActivityStocksKey(Long activityId, Long commoditySkuId) {
        return String.format(ACTIVITY_STOCKS_kEY_FORMAT, getActivityType(), commoditySkuId, activityId);
    }

    /**
     * 增加用户购买
     */
    public Long customerPurchase(Long customerId, Long commoditySkuId, Integer quantity) {
        String key = formatCustomerPurchaseKey(customerId, commoditySkuId);
        Long increment = commodityActivityRedisUtil.increment(key, quantity);
        ActivityInfo activity = getActivityInfo(commoditySkuId);
        if (ObjectUtil.isNull(activity)) {
            throw new CommodityActivityException("商品关联秒杀活动不存在或已结束");
        }
        long seconds = Duration.between(LocalDateTime.now(), activity.getEndTime()).toSeconds();
        commodityActivityRedisUtil.keepAlive(key, (int) seconds, TimeUnit.SECONDS);
        return increment;
    }

    private String formatCustomerPurchaseKey(Long customerId, Long commoditySkuId) {

        return String.format(CUSTOMER_PURCHASE_kEY_FORMAT, getActivityType(), commoditySkuId, customerId);
    }


    /**
     * 获取当前用户已购数量，用于限购使用
     */
    public Long getCustomerPurchaseNumber(Long customerId, Long commoditySkuId) {
        return customerPurchase(customerId, commoditySkuId, 0);
    }

    /**
     * 获取redis分布式锁
     */
    public boolean getLock() {
        String activityType = getActivityType();
        return commodityActivityRedisUtil.getLock(activityType,activityType);
    }

    /**
     * 释放锁
     */
    public void unLock() {
        commodityActivityRedisUtil.unLock(getActivityType());
    }
}
